/** Fichier définissant l'interface d'une forme.
 *
 * Ce fichier contient la définition de la classe abstraite Forme.
 *
 * @file Forme.hpp
 * @author Jean-Marc Combi
 * @author Romain Dequesne
 * @author Johan "Solo" Luisier
 *
 * @date 06 Avril 2004
 */
#ifndef _FORME_H
#define _FORME_H

#include <iostream>

#include "Algebre/Coord.hpp"
#include "Algebre/Vecteur.hpp"
#include "Algebre/Transformation.hpp"

#include "Noyau/Rayon.hpp"

class Solveur;

/** Classe abstraite dérivant une forme géométrique.
 *
 * Une forme est définie par un champ de normale et une surface. Les deux
 * méthodes cruciales sont donc intersect (qui calcule le point d'intersection
 * avec la surface) et normale (qui donne la valeur de la normale en un point
 * de la surface).
 *
 * Comme certaines formes sont définies dans un système de coordonnées locales,
 * la classe contient un champ Transformation, qui permet de faire une rotation,
 * une rotation et une homothétie.
 *
 * @author Jean-Marc Combi
 * @author Romain Dequesne
 * @author Johan "Solo" Luisier
 *
 * @date 06 Avril 2004
 *
 * @class Forme "Forme.hpp" "Formes/Forme.hpp"
 */
class Forme
{
public:
    Forme( const std::string& nom, const Transformation& tr = Transformation() );
    virtual ~Forme();
    virtual bool aIntersection( const Rayon& rayon ) const;
    /**
     * Calcule le point d'intersection du Rayon avec la Forme. Le calcul
     * peut se faire en coordonnées locales ou globales, mais le
     * résultat est toujours en coordonnées globales.
     *
     * @param[in] ray rayon, lancé par la caméra ou un autre objet.
     *
     * @return le point d'intersection.
     */
    virtual Coord trouveIntersection(const Rayon& ray) const = 0;
    /**
     * Calcule la valeur du champ de normale au point donné. Attention,
     * la plupart du temps in ne vérifie pas que le point soit bien sur
     * la surface !
     *
     * @param coord point de la surface.
     * @return normale en ce point.
     */
    virtual VecteurU normale(const Coord& coord) const = 0;
    /**
     * Permet de vérifier si un point est \e à \e l'intérieur d'une
     * forme.
     *
     * @param coord point à tester.
     * @return \e true si le point est à l'intérieur, \e false sinon.
     */
    virtual bool estDans(const Coord& coord) const = 0;
    /**
     * Permet de vérifier si un point est \e à \e la \e surface d'une
     * forme. On donne une tolérance de 1e-7 pour faire le test.
     *
     * @param coord point à tester.
     * @return \e true si le point est à la surface, \e false sinon.
     */
    virtual bool estSur(const Coord& coord) const = 0;

    virtual void mapping( const Coord &, int &i, int &j, const int &frequence,
                          const int &Hauteur, const int &Largeur ) const;

    /**
     * Permet d'afficher le nom et les paramètres de la forme.
     *
     * @param os flot de sortie dans lequel les informations seront
     * écrites.
     * @return référence sur le flot de sortie modifié.
     */
    virtual std::ostream& affiche(std::ostream& os) const = 0;
    const Coord& pseudoCentre() const;
    const double& pseudoRayon() const;
    const std::string& nom() const;
    /**
     * Permet de récupérer un point de la surface dans les coordonnées
     * intrinsèques.
     *
     * @param pt point de la surface que l'on voudait obtenir en
     * coordonnées intrinsèques.
     * @return les coordonnées intrinsèques de pt, sous la forme d'un
     * Coord dont la composante z est nulle.
     */
    virtual Coord intrinseque(const Coord& pt) const = 0;
    virtual Coord intrinsequeReduite(const Coord& pt, const double& larg) const;
    const Transformation& versGlobal() const;
    const Transformation& versLocal() const;
protected:
    /**
     * Transformation de l'espace permettant de passer du système de
     * coordonnées locales au coordonées globales.
     */
    Transformation VersGlobal;
    /**
     * Transformation de l'espace permettant de passer du système de
     * coordonnées globales au coordonées locales.
     */
    Transformation VersLocal;
    /**
     * Nom de la forme.
     */
    std::string Nom;
    /**
     * Point central d'une forme, peut être le centre de gravité, qui
     * sert à localiser grossièrement la forme dans l'espace.
     */
    Coord PseudoCentre;
    /**
     * Rayon définissant la sphère dans laquelle le solide est
     * inscrit. Est utilisé pour déterminer si un rayon donné a une
     * chance d'avoir une intersection avec la forme.
     */
    double PseudoRayon;
    /**
     * Solveur numérique pour trouver les intersections.
     */
    Solveur* MoteurResolution;
    /**
     * Valeur de @f$ \pi @f$, utilisée pour les formes faisant
     * intervenir cette valeur dans leur équation.
     */
    static const double ValeurPi;
};

#endif
